package com.pactera.madp.cp.common.util.file;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil;
import com.pactera.madp.cp.common.constant.Constant;
import com.pactera.madp.cp.config.WxProxyConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.fileupload.disk.DiskFileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.springframework.http.MediaType;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Proxy;

/**
 * @author lx
 * @date 2021/7/15
 * @desc 文件上传处理类
 */
@Component
@Slf4j
public class MultipartFileHandler extends BaseFileHandler {

    /**
     * 多类型文件上传处理
     * @param t
     * @param fileKey
     * @param isCover
     * @param <T>
     * @return
     */
    @Override
    public <T> FileProps handFileUpload(T t, String fileKey, boolean isCover) {
        FileProps props = null;
        if(t == null) {
            return props;
        }

        if(t instanceof MultipartFile) {
            props = uploadFile((MultipartFile)t, fileKey, isCover);
        }
        else if(t instanceof File) {
            if(StrUtil.isEmpty(fileKey)) {
                fileKey = ((File) t).getName();
            }
            props = uploadFile((File)t, fileKey, isCover);
        }
        else if(t instanceof InputStream) {
            props = uploadFile((InputStream)t, fileKey, isCover);
        }
        else if(t instanceof String) {
            if(((String) t).endsWith("==")) {
                props = uploadFile((String)t, fileKey, isCover);
            }else {
                props = uploadFileByURL((String)t, fileKey);
            }

        }

        return props;
    }

    @Override
    public <T> FileProps handFileUpload(T t, String fileKey, boolean isCover, boolean isUpload) {
        FileProps props = null;
        if(t == null) {
            return props;
        }

        if(t instanceof MultipartFile) {
            props = uploadFile((MultipartFile)t, fileKey, isCover);
        }
        else if(t instanceof File) {
            if(StrUtil.isEmpty(fileKey)) {
                fileKey = ((File) t).getName();
            }
            props = uploadFile((File)t, fileKey, isCover);
        }
        else if(t instanceof InputStream) {
            props = uploadFile((InputStream)t, fileKey, isCover);
        }
        else if(t instanceof String) {
            if(((String) t).endsWith("==")) {
                props = uploadFile((String)t, fileKey, isCover);
            }else {
                props = uploadFileByURL((String)t, fileKey, isUpload);
            }

        }

        return props;
    }

    /**
     * MultipartFile文件上传
     * @param file
     * @param fileKey  可包含文件路径
     * @param isCover
     * @return
     */
    @Override
    public FileProps uploadFile(MultipartFile file, String fileKey, boolean isCover){
        try {
            FileProps props = getFileProps(file, fileKey, isCover);
            doUploadFile(file, props.getDest());
            props.setSucceed(true);
            return props;
        }catch (Exception e) {
            log.error(e.getMessage());
        }
        return null;
    }

    @Override
    public FileProps uploadFile(MultipartFile file, String fileKey, boolean isCover, boolean isUpload){
        try {
            FileProps props = getFileProps(file, fileKey, isCover);
            if (isUpload) {
                doUploadFile(file, props.getDest());
            }
            props.setSucceed(true);
            return props;
        }catch (Exception e) {
            log.error(e.getMessage());
        }
        return null;
    }

    /**
     * 文件类型上传
     * @param file
     * @param fileKey
     * @param isCover
     * @return
     */
    @Override
    public FileProps uploadFile(File file, String fileKey, boolean isCover){
        try {
            MultipartFile multipartFile = fileToMultipartFile(file, fileKey);
            return uploadFile(multipartFile, fileKey, isCover);
        }catch (Exception e) {
            log.error(e.getMessage());
        }
        return null;
    }

    /**
     * 流文件上传
     * @param in
     * @param fileKey
     * @param isCover
     * @return
     */
    @Override
    public FileProps uploadFile(InputStream in, String fileKey, boolean isCover) {
        MultipartFile file = streamToMultipartFile(in, fileKey);
        return uploadFile(file, fileKey, true);
    }

    @Override
    public FileProps uploadFile(InputStream in, String fileKey, boolean isCover, boolean isUpload) {
        MultipartFile file = streamToMultipartFile(in, fileKey);
        return uploadFile(file, fileKey, true, isUpload);
    }

    /**
     * base64文件上传
     * @param base64
     * @param fileKey
     * @param isCover
     * @return
     */
    @Override
    public FileProps uploadFile(String base64, String fileKey, boolean isCover) {
        MultipartFile multipartFile = base64ToMultipartFile(base64);
        return uploadFile(multipartFile, fileKey, isCover);
    }

    /**
     * 网络文件上传
     * @param fileUrl
     * @param fileKey
     * @return
     */
    @Override
    public FileProps uploadFileByURL(String fileUrl, String fileKey){
        InputStream in = null;
        try {
            HttpRequest httpRequest = HttpUtil.createGet(fileUrl);
            //设置代理
            if (WxProxyConfig.isEnabled()) {
                Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(WxProxyConfig.getIp(), WxProxyConfig.getPort()));
                httpRequest.setProxy(proxy);
            }
            in = httpRequest.execute(true).bodyStream();
//            in = HttpUtil.createGet(fileUrl).execute(true).bodyStream();
        }catch (Exception e) {
            log.error(e.getMessage());
            log.error("网络文件获取失败：{}", fileUrl);
            return null;
        }
        return uploadFile(in, fileKey, true);
    }

    @Override
    public FileProps uploadFileByURL(String fileUrl, String fileKey, boolean isUpload) {
        InputStream in = null;
        try {
            HttpRequest httpRequest = HttpUtil.createGet(fileUrl);
            //设置代理
            if (WxProxyConfig.isEnabled()) {
                Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(WxProxyConfig.getIp(), WxProxyConfig.getPort()));
                httpRequest.setProxy(proxy);
            }
            in = httpRequest.execute(true).bodyStream();
        }catch (Exception e) {
            log.error("网络文件获取失败：{}", fileUrl);
            return null;
        }
        return uploadFile(in, fileKey, true, isUpload);
    }


    /**
     * File转MultipartFile
     * @param file
     * @param fileKey
     * @return
     */
    private MultipartFile fileToMultipartFile(File file, String fileKey) {
        InputStream in = FileUtil.getInputStream(file);
        return streamToMultipartFile(in, fileKey);
    }

    /**
     * stream转MultipartFile
     * @param in
     * @param fileKey
     * @return
     */
    private MultipartFile streamToMultipartFile(InputStream in, String fileKey) {
        if(in == null) {
            throw new IllegalArgumentException("文件流不能为空");
        }
        if(StrUtil.isEmpty(fileKey)) {
            throw new IllegalArgumentException("文件Key不能为空");
        }
        //如果包含“/”，则直接获取文件名
        String fileName = fileKey;
        if(fileKey.contains(Constant.SEPARATOR)) {
            int separatorIndex = fileKey.lastIndexOf(Constant.SEPARATOR);
            fileName = fileKey.substring(separatorIndex + 1);
        }

        DiskFileItem fileItem = (DiskFileItem) new DiskFileItemFactory().createItem("file",
                MediaType.ALL_VALUE, true, fileName);
        try {
            OutputStream os = fileItem.getOutputStream();
            IoUtil.copy(in,os);
        } catch (Exception e) {
            throw new IllegalArgumentException("Invalid file: " + e, e);
        }

        MultipartFile multi = new CommonsMultipartFile(fileItem);
        return multi;
    }

    /**
     * base64转MultipartFile
     * @return
     */
    private MultipartFile base64ToMultipartFile(String base64) {
        return BASE64DecodedMultipartFile.base64ToMultipart(base64);
    }

    /**
     * 获取文件属性
     * @param file
     * @param fileKey
     * @param isCover
     * @return
     */
    private FileProps getFileProps(MultipartFile file, String fileKey, boolean isCover) {
        if(file == null) {
            throw new IllegalArgumentException("文件不能为空");
        }
        if(FilesUtil.getConfig().getRealPath() == null) {
            throw new IllegalArgumentException("文件存储路径不存在");
        }
        if(FilesUtil.getConfig().getAccessPath() == null) {
            throw new IllegalArgumentException("文件访问Path不存在");
        }

        String path = "";
        String original = file.getOriginalFilename();
        String extName = FileUtil.extName(original);
        String fileName = fileKey;
        if(StrUtil.isEmpty(fileKey)) {
            //文件名为空使用默认的
            fileName = IdUtil.simpleUUID() + StrUtil.DOT + extName;
        }else if(fileKey.contains(Constant.SEPARATOR)) {
            //文件名包含路径处理
            int separatorIndex = fileKey.lastIndexOf(Constant.SEPARATOR);
            path = fileKey.substring(0,separatorIndex);
            path = path.startsWith(Constant.SEPARATOR) ? path : Constant.SEPARATOR + path;
            fileName = fileKey.substring(separatorIndex + 1);

            if(fileName.lastIndexOf(StrUtil.C_DOT) > 0) {
                int dotIndex = fileName.lastIndexOf(StrUtil.C_DOT);
                extName = fileName.substring(dotIndex + 1);
            }
        }
        String dest = FilesUtil.getConfig().getRealPath() + path + Constant.SEPARATOR + fileName;

        File parentFile = new File(dest).getParentFile();
        if(!parentFile.exists()) {
            parentFile.mkdirs();
        }

        if(isCover) {
            //校验文件是否存在
            File alreadyFile = new File(dest);
            if(alreadyFile.exists()) {
                alreadyFile.delete();
            }
        }
        String url = FilesUtil.getConfig().getAccessPath() + path + Constant.SEPARATOR + fileName;

        FileProps props = new FileProps();
        props.setOriginal(original);
        props.setFileName(fileName);
        props.setType(extName);
        props.setDest(dest);
        props.setFileSize(file.getSize());
        props.setUrl(url);
        props.setBucketName(path);

        return props;
    }

    /**
     * 上传文件
     * @param file
     * @param dest
     * @throws Exception
     */
    @Async
    public void doUploadFile(MultipartFile file, String dest) throws Exception{
        file.transferTo(new File(dest));
    }
}
